#ifndef __LOGGER_HPP___
#define __LOGGER_HPP___

#include <iostream>
#include <vector>
#include <atomic>
#include <mutex>
#include <memory>
#include <cstdarg>
#include <functional>
#include <unordered_map>
#include "Until.hpp"
#include "Level.hpp"
#include "Format.hpp"
#include "Message.hpp"
#include "Sink.hpp"

#include "Looper.hpp"

namespace Logs
{
    class Logger
    {
    public:
        using Ptr = std::shared_ptr<Logger>;

        Logger( Level::Value& limit_level
            , Formatter::Ptr& formatter
            ,const std::string& logger_name
            ,std::vector<Sink::Ptr>& sinks
            )
            :_limit_level(limit_level)
            ,_formatter(formatter)
            ,_logger_name(logger_name)
            ,_sinks(sinks.begin(),sinks.end())
        {
            ;
        }
        const std::string& loggerName()
        {
            return _logger_name;
        }
        void debug(const std::string& file,size_t line,const std::string& fmt,...)
        {
            if(Level::Value::DEBUG < _limit_level)
            {
                return ;
            }
            va_list ap;
            va_start(ap,fmt);
            char* res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret == -1)
            {
                std::cout << "vasprintf failed!!\n";

                return ;
            }
            va_end(ap);
            Serialize(Level::Value::DEBUG,file,line,res);

            free(res);
        }
        void info(const std::string& file,size_t line,const std::string& fmt,...)
        {
            if(Level::Value::INFO < _limit_level)
            {
                return ;
            }
            va_list ap;
            va_start(ap,fmt);
            char* res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret == -1)
            {
                std::cout << "vasprintf failed!!\n";

                return ;
            }
            va_end(ap);
            Serialize(Level::Value::INFO,file,line,res);
            
            free(res);
        }
        void warn(const std::string& file,size_t line,const std::string& fmt,...)
        {
            if(Level::Value::WARN < _limit_level)
            {
                return ;
            }
            va_list ap;
            va_start(ap,fmt);
            char* res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret == -1)
            {
                std::cout << "vasprintf failed!!\n";

                return ;
            }
            va_end(ap);
            Serialize(Level::Value::WARN,file,line,res);
            
            free(res);
        }
        void error(const std::string& file,size_t line,const std::string& fmt,...)
        {
            if(Level::Value::ERROR < _limit_level)
            {
                return ;
            }
            va_list ap;
            va_start(ap,fmt);
            char* res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret == -1)
            {
                std::cout << "vasprintf failed!!\n";

                return ;
            }
            va_end(ap);
            Serialize(Level::Value::ERROR,file,line,res);
            
            free(res);
        }
        void fatal(const std::string& file,size_t line,const std::string& fmt,...)
        {
            if(Level::Value::FATAL < _limit_level)
            {
                return ;
            }
            va_list ap;
            va_start(ap,fmt);
            char* res;
            // vasprintf根据不定参数的列表中的数据进行字符串的初始化。
            // 这res是动态申请的资源，记得释放。
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret == -1)
            {
                std::cout << "vasprintf failed!!\n";

                return ;
            }
            va_end(ap);
            Serialize(Level::Value::FATAL,file,line,res);
            
            free(res);
        }
    //protected:
        virtual void log(const char* str,size_t len) = 0;
        void Serialize(Level::Value level,const std::string& file,size_t line,char* res)
        {
            Message msg(Until::Time::GetTime(),level,file,line,res,_logger_name);
            std::stringstream ss;
            //ss << res << "\n";
            _formatter->format(ss,msg);
            log(ss.str().c_str(),ss.str().size());
        }
    protected:
        std::mutex _mutex;
        std::atomic<Level::Value> _limit_level;
        Formatter::Ptr _formatter;
        std::string _logger_name;
        std::vector<Sink::Ptr> _sinks;
    };
    // 同步日志器。
    class SyncLogger : public Logger
    {
    public:
        SyncLogger(Level::Value& limit_level
            ,Formatter::Ptr& formatter
            ,const std::string& logger_name
            ,std::vector<Sink::Ptr>& sinks
            )
            :Logger(limit_level,formatter,logger_name,sinks)
        {
            ;
        }
        void log(const char* str,size_t len) override
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            if(_sinks.empty())
            {
                return ;
            }
            for(auto& sink : _sinks)
            {
                sink->log(str,len);
            }
        }
    private:
    };
    // 异步日志器。
    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(Level::Value limit_level
                    ,Formatter::Ptr formatter
                    ,const std::string&  logger_name
                    ,std::vector<Sink::Ptr>& sinks
                    ,AsyncType looper_type = AsyncType::ASYNC_SAFE)
            :Logger(limit_level,formatter,logger_name,sinks)
            ,_looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog,this,std::placeholders::_1),looper_type))
            ,_looper_type(looper_type)
        {
            std::cout << Level::To_String(_limit_level) << "异步日志器: " << _logger_name << "创建成功...\n";
            std::cout << "sink:" << _sinks.size() << "\n";
        }
        // push进缓冲区。 
        void log(const char* str,size_t len) override
        {
            _looper->push(str,len);
        }
        // 设计一个实际落地函数。(将缓冲区的内容落地)
        void realLog(Buffer& buffer)
        {
            if(_sinks.empty())
            {
                return ;
            }
            std::cout << _sinks.size() << std::endl;
            for(auto& sink : _sinks)
            {
                sink->log(buffer.begin(),buffer.readAbleLen());
            }
        }
    private:
        AsyncLooper::Ptr _looper;
        AsyncType _looper_type;
    };

    enum class LoggerType
    {
        LOGGER_ASYNC,
        LOGGER_SYNC
    };

    class LoggerBuilder
    {
    public:
        using Ptr = std::shared_ptr<LoggerBuilder>;
        // LoggerBuilder(LoggerType logger_type
        //            ,AsyncType looper_type
        //            ,Level::Value limit_level
        //            //,Formatter::Ptr& formatter
        //            ,const std::string& logger_name
        //            //,std::vector<Sink::Ptr>& sinks
        //            )
        //     :_logger_type(logger_type)
        //     ,_limit_level(limit_level)
        //     //,_formatter(formatter)
        //     ,_logger_name(logger_name)
        //     //,_sinks(sinks.begin(),sinks.end())
        //     ,_looper_type(looper_type) // 默认是安全的。
        // {
        //     ;
        // }
        LoggerBuilder()
            :_limit_level(Level::Value::DEBUG)
            ,_logger_type(LoggerType::LOGGER_SYNC)
            ,_looper_type(AsyncType::ASYNC_SAFE)
        {}
        void BuildLoggerType(LoggerType type)// 调整为不安全的。
        {
            _logger_type = type;
        }
        void BuildAsyncUnsafe()
        {
            _looper_type = AsyncType::ASYNC_UNSAFE;
        }
        void BuildLoggerName(const std::string& name)
        {
            _logger_name = name;
        }
        void BuildLoggerLevel(Level::Value level)
        {
            _limit_level = level;
        }
        void BuildFormatter(const std::string& pattern)
        {
            _formatter = std::make_shared<Formatter>(pattern);
        }

        template< typename SinkType , typename ...Args >
        void BuildSink(Args&& ...args)
        {
            Sink::Ptr psink = SinkFactory::CreateSink<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }

        virtual Logger::Ptr Build() = 0;
    protected:
        LoggerType _logger_type;
        AsyncType _looper_type;
        Level::Value _limit_level;
        Formatter::Ptr _formatter;
        std::string _logger_name;
        std::vector<Sink::Ptr> _sinks;
    };

    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        // LocalLoggerBuilder(LoggerType logger_type
        //            ,Level::Value limit_level
        //            //,Formatter::Ptr& formatter
        //            ,const std::string& logger_name
        //            //,std::vector<Sink::Ptr>& sinks
        //            ,AsyncType looper_type = AsyncType::ASYNC_SAFE
        //            )
        //     :LoggerBuilder(logger_type,looper_type,limit_level,logger_name)
        // {
        //     ;
        // }
        LocalLoggerBuilder()
            :LoggerBuilder()
        {}
        Logger::Ptr Build() override
        {
            // 日志器的名字是查找日志器的唯一凭证。
            // 不可或缺。
            assert(_logger_name.size());
            // 接下来再慢慢改。
            if(_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if(_sinks.empty())
            {
                BuildSink<StdoutSink>();
            }
            // 异步日志器
            if(_logger_type == LoggerType::LOGGER_ASYNC)
            {
                // Level::Value limit_level
                //     ,Formatter::Ptr formatter
                //     ,const std::string&  logger_name
                //     ,std::vector<Sink::Ptr>& sinks
                //     ,AsyncType looper_type = AsyncType::ASYNC_SAFE
                std::cout << "制造异步日志器" << std::endl;
                std::cout <<"_sinks:" << _sinks.size() << "\n";
                return std::make_shared<AsyncLogger>(_limit_level,_formatter,_logger_name,_sinks,_looper_type);
            }

            // 同步日志器
            // Level::Value& limit_level
            // ,Formatter::Ptr& formatter
            // ,const std::string& logger_name
            // ,std::vector<Sink::Ptr>& sinks
            return std::make_shared<SyncLogger>(_limit_level,_formatter,_logger_name,_sinks);
        }
    };

    class LoggerManager
    {
    public:
        static LoggerManager& getInc()
        {
            // static 是有线程安全的，不用担心会创建多个static对象。
            static LoggerManager self;
            return self;
        }
        void addLogger(Logger::Ptr logger)
        {
            // 访问公共资源时记得加锁。
            if(hasLogger(logger->loggerName()))
            {
                return ;
            }
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->loggerName(),logger));
        }
        bool hasLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            std::unordered_map<std::string,Logger::Ptr>::iterator pos = _loggers.find(name);
            if(pos == _loggers.end())
            {
                return false;
            }

            return true;
        }
        Logger::Ptr getLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            std::unordered_map<std::string,Logger::Ptr>::iterator pos = _loggers.find(name);
            if(pos == _loggers.end())
            {
                return nullptr;
            }

            return pos->second;
        }
        Logger::Ptr rootLogger()
        {
            return _root_logger;
        }
    private:
        // LoggerManage(LoggerType logger_type
        //            ,Level::Value limit_level
        //            //,Formatter::Ptr& formatter
        //            ,const std::string& logger_name
        //            //,std::vector<Sink::Ptr>& sinks
        //            ,AsyncType looper_type = AsyncType::ASYNC_SAFE)
        LoggerManager()
        {
            std::unique_ptr<LoggerBuilder> build(std::make_unique<LocalLoggerBuilder>());
            build->BuildLoggerName("root");
            _root_logger = build->Build();
            _loggers.insert(std::make_pair("root",_root_logger));
        }
    private:
        std::mutex _mutex; 
        Logger::Ptr _root_logger; // 默认日志器。
        std::unordered_map<std::string,Logger::Ptr> _loggers;
    };
    
    // 设计一个全局日志器制造者。
    class GlobalLoggerBuilder : public LoggerBuilder
    {
    public:
        // LocalLoggerBuilder(LoggerType logger_type
        //            ,Level::Value limit_level
        //            //,Formatter::Ptr& formatter
        //            ,const std::string& logger_name
        //            //,std::vector<Sink::Ptr>& sinks
        //            ,AsyncType looper_type = AsyncType::ASYNC_SAFE
        //            )
        //     :LoggerBuilder(logger_type,looper_type,limit_level,logger_name)
        // {
        //     ;
        // }
        GlobalLoggerBuilder(){}
        Logger::Ptr Build() override
        {
            // 日志器的名字是查找日志器的唯一凭证。
            // 不可或缺。
            assert(_logger_name.size());
            // 接下来再慢慢改。
            if(_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if(_sinks.empty())
            {
                BuildSink<StdoutSink>();
            }

            Logger::Ptr logger;

            // 异步日志器
            if(_logger_type == LoggerType::LOGGER_ASYNC)
            {
                logger = std::make_shared<AsyncLogger>(_limit_level,_formatter,_logger_name,_sinks,_looper_type);
            }

            std::make_shared<SyncLogger>(_limit_level,_formatter,_logger_name,_sinks);
            
            LoggerManager::getInc().addLogger(logger);
            return logger;
        }
    };
}

#endif